/*
 * MegaMek - Copyright (C) 2002,2003,2004 Ben Mazur (bmazur@sev.org)
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 */

/*
 * EquipmentType.java
 *
 * Created on April 1, 2002, 1:35 PM
 */

package megamek.common;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

/**
 * Represents any type of equipment than can be mounted on a mech. This excludes
 * systems and actuators.
 * 
 * @author Ben
 * @version
 */
public class EquipmentType
{

	/** The constant TONNAGE_VARIABLE. */
	public static final float TONNAGE_VARIABLE = Float.MIN_VALUE;

	/** The constant CRITICALS_VARIABLE. */
	public static final int CRITICALS_VARIABLE = Integer.MIN_VALUE;

	/** The constant BV_VARIABLE. */
	public static final int BV_VARIABLE = Integer.MIN_VALUE;

	/** The constant COST_VARIABLE. */
	public static final int COST_VARIABLE = Integer.MIN_VALUE;

	/** Armor constant: armor unknown. */
	public static final int T_ARMOR_UNKNOWN = -1;

	/** Armor constant: standard armor. */
	public static final int T_ARMOR_STANDARD = 0;

	/** Armor constant: ferro fibrous. */
	public static final int T_ARMOR_FERRO_FIBROUS = 1;

	/** Armor constant: reactive armor. */
	public static final int T_ARMOR_REACTIVE = 2;

	/** Armor constant: reflective armor. */
	public static final int T_ARMOR_REFLECTIVE = 3;

	/** Armor constant: hardened armor. */
	public static final int T_ARMOR_HARDENED = 4;

	/** Armor constant: light ferro. */
	public static final int T_ARMOR_LIGHT_FERRO = 5;

	/** Armor constant: heavy ferro. */
	public static final int T_ARMOR_HEAVY_FERRO = 6;

	/** Armor constant: patchwork armor. */
	public static final int T_ARMOR_PATCHWORK = 7;

	/** Armor constant: stealth armor. */
	public static final int T_ARMOR_STEALTH = 8;

	/** Armor constant: ferro fibrous proto. */
	public static final int T_ARMOR_FERRO_FIBROUS_PROTO = 9;

	/** Armor constant: commercial armor. */
	public static final int T_ARMOR_COMMERCIAL = 10;

	/** Armor constant: /** armor constant: ferro carbide. */
	public static final int T_ARMOR_FERRO_CARBIDE = 11;

	/** Armor constant: lamellor ferro carbide. */
	public static final int T_ARMOR_LAMELLOR_FERRO_CARBIDE = 12;

	/** Armor constant: ferro imp. */
	public static final int T_ARMOR_FERRO_IMP = 13;

	/** Armor constant: industrial armor. */
	public static final int T_ARMOR_INDUSTRIAL = 14;

	/** Armor constant: heavy industrial armor. */
	public static final int T_ARMOR_HEAVY_INDUSTRIAL = 15;

	/** Structure constant: unknown structure. */
	public static final int T_STRUCTURE_UNKNOWN = -1;

	/** Structure constant: standard structure. */
	public static final int T_STRUCTURE_STANDARD = 0;

	/** Structure constant: endo steel structure. */
	public static final int T_STRUCTURE_ENDO_STEEL = 1;

	/** Structure constant: endo prototype structure. */
	public static final int T_STRUCTURE_ENDO_PROTOTYPE = 2;

	/** Structure constant: reinforced structure. */
	public static final int T_STRUCTURE_REINFORCED = 3;

	/** Structure constant: composite structure. */
	public static final int T_STRUCTURE_COMPOSITE = 4;

	/** Structure constant: industrial structure. */
	public static final int T_STRUCTURE_INDUSTRIAL = 5;

	/** The armor names constant. */
	public static final String[] ARMOR_NAMES = { "Standard", "Ferro-Fibrous",
			"Reactive", "Reflective", "Hardened", "Light Ferro-Fibrous",
			"Heavy Ferro-Fibrous", "Patchwork", "Stealth",
			"Ferro-Fibrous Prototype", "Commercial", "Ferro-Carbide",
			"Lamellor Ferro-Carbide", "Improved Ferro-Aluminum", "Industrial",
			"Heavy Industrial" };

	/** The structure names constant. */
	public static final String[] STRUCTURE_NAMES = { "Standard", "Endo Steel",
			"Endo Steel Prototype", "Reinforced", "Composite", "Industrial" };

	/** The structure levels constant. */
	public static final int[] STRUCTURE_LEVELS = { 1, 2, 3, 3, 3 };

	/**
	 * The structure costs constant. Assume for now that the prototype is more
	 * expensive.
	 */
	public static final double[] STRUCTURE_COSTS = { 400, 1600, 1600, 6400,
			3200, 300 };

	/**
	 * The armor costs constant. Assume for now that the prototype is more
	 * expensive.
	 */
	public static final double[] ARMOR_COSTS = { 10000, 20000, 30000, 30000,
			15000, 15000, 25000, /* patchwork) */50000, 50000, 20000, 3000,
			75000, 100000, 50000, 5000, 10000 };

	/** The armor point multipliers constant. */
	public static final double[] ARMOR_POINT_MULTIPLIERS = { 1, 1.12, 1, 1, 1,
			1.06, 1.24, 1, 1, 1.12, 1.5, 1, 1, 1, 0.67, 1.0 };

	/** The POINT_MULTIPLIER_UNKNOWN constant. */
	public static final double POINT_MULTIPLIER_UNKNOWN = 1;

	/** The POINT_MULTIPLIER_CLAN_FF constant. */
	public static final double POINT_MULTIPLIER_CLAN_FF = 1.2;

	/** The name of this of equipment. */
	protected String name = null;

	/** The internal name of this equipment. */
	protected String internalName = null;

	/** The names vector. */
	private Vector<String> namesVector = new Vector<String>();

	/** The tonnage of this equipment. */
	protected float tonnage = 0;

	/** The criticals of this equipment. */
	protected int criticals = 0;

	/** Whether or not this equipment is explosive. */
	protected boolean explosive = false;

	/** Whether or not this equipment is hittable. */
	protected boolean hittable = true; // if false, reroll critical hits

	/**
	 * Whether or not the crits for this equipment can be spread over different
	 * locations.
	 */
	protected boolean spreadable = false;

	/** The to hit modifier of this equipment. */
	protected int toHitModifier = 0;

	/** The technical level of this equipment. */
	protected int techLevel = TechConstants.T_TECH_UNKNOWN;

	/** This equipment's flags. */
	protected long flags = 0;

	/** The sub type of this equipment. */
	protected long subType = 0;

	/** The battle value point system. */
	protected double battleValue = 0; //

	/** The cost of this equipment. */
	protected double cost = 0; // The C-Bill cost of the item.

	/** The modes this equipment can be in. */
	protected Vector<EquipmentMode> modes = null;

	/**
	 * Whether or not this equipment's modes is switched instantly or at the end
	 * of a turn.
	 */
	protected boolean instantModeSwitch = true;

	/**
	 * Stores the end of turn modes for an equipment whose modes can be switched
	 * at the end of a turn.
	 */
	public Vector<String> endTurnModes = new Vector<String>();

	/** The list of equipments. */
	protected static Vector<EquipmentType> allTypes;

	/** The lookup hash. */
	protected static Hashtable<String, EquipmentType> lookupHash;



	/**
	 * Creates new EquipmentType.
	 */
	public EquipmentType() {

	}



	/**
	 * Sets the flags.
	 * 
	 * @param flags the value to store as the flags.
	 */
	public void setFlags(long flags)
	{
		this.flags = flags;
	}



	/**
	 * Sets the sub type.
	 * 
	 * @param newFlags the value to store as the sub type.
	 */
	public void setSubType(int newFlags)
	{
		subType = newFlags;
	}



	/**
	 * Adds the sub type.
	 * 
	 * @param newFlag the value used to create a new sub type.
	 */
	public void addSubType(int newFlag)
	{
		subType |= newFlag;
	}



	/**
	 * Determines whether there is a sub type.
	 * 
	 * @param testFlag the test flag the value to look for the sub type for.
	 * @return true if there is a sub type.
	 */
	public boolean hasSubType(long testFlag)
	{
		return (subType & testFlag) != 0;
	}



	/**
	 * Gets the name of this equipment.
	 * 
	 * @return the name of this equipment.
	 */
	public String getName()
	{
		return name;
	}



	/**
	 * Gets the description of this equipment.
	 * 
	 * @return the description of this equipment.
	 */
	public String getDesc()
	{
		String result = EquipmentMessages.getString("EquipmentType." + name);

		if (result != null) {
			return result;
		}

		return name;
	}



	/**
	 * Gets the internal name of this equipment.
	 * 
	 * @return the internal name of this equipment.
	 */
	public String getInternalName()
	{
		return internalName;
	}



	/**
	 * Gets the technical level of this equipment.
	 * 
	 * @return the technical level of this equipment.
	 */
	public int getTechLevel()
	{
		return techLevel;
	}



	/**
	 * Gets the tonnage of this equipment.
	 * 
	 * @param entity the entity whose tonnage is being retrieved.
	 * @return the tonnage of this equipment.
	 */
	public float getTonnage(Entity entity)
	{
		return tonnage;
	}



	/**
	 * Sets the tonnage of this equipment.
	 * 
	 * @param tonnage the value to store as the tonnage.
	 */
	public void setTonnage(float tonnage)
	{
		this.tonnage = tonnage;
	}



	/**
	 * Gets the criticals.
	 * 
	 * @param entity the entity whose criticals is being retireved.
	 * @return the criticals.
	 */
	public int getCriticals(Entity entity)
	{
		return criticals;
	}



	/**
	 * Determines whether this equipment is explosive.
	 * 
	 * @return true if the equipment is explosive.
	 */
	public boolean isExplosive()
	{
		return explosive;
	}



	/**
	 * Checks if this equipment is hittable.
	 * 
	 * @return true if this equipment is hittable.
	 */
	public boolean isHittable()
	{
		return hittable;
	}



	/**
	 * Checks if is equipment is spreadable.
	 * 
	 * @return true if is equipment is spreadable.
	 */
	public boolean isSpreadable()
	{
		return spreadable;
	}



	/**
	 * Gets the to hit modifier of this equipment.
	 * 
	 * @return the to hit modifier.
	 */
	public int getToHitModifier()
	{
		return toHitModifier;
	}



	/**
	 * Gets the flags.
	 * 
	 * @return the flags.
	 */
	public long getFlags()
	{
		return flags;
	}



	/**
	 * Checks if this equipment has a flag.
	 * 
	 * @param flag the flag to determine if
	 * @return true if there is a flag for this equipment.
	 */
	public boolean hasFlag(long flag)
	{
		return (flags & flag) != 0;
	}



	/**
	 * Gets the battle value.
	 * 
	 * @param entity the entity whose battle value is being retrieved.
	 * @return the battle value.
	 */
	public double getBattleValue(Entity entity)
	{
		return battleValue;
	}



	/**
	 * Checks if this equipment has any modes it can be in.
	 * 
	 * @return true if this type of equipment has any modes.
	 */
	public boolean hasModes()
	{
		return modes != null;
	}



	/**
	 * Gets the number of modes this equipment can have.
	 * 
	 * @return the number of modes this type of equipment can be in or
	 *         <code>0</code> if it doesn't have modes.
	 */
	public int getModesCount()
	{
		int count;

		if (modes == null) {
			count = 0;
		}
		else {
			count = modes.size();
		}

		return count;
	}



	/**
	 * Gets the modes than an equipment can be in.
	 * 
	 * @return an <code>Enumeration</code> of the modes this type of equipment
	 *         can be in.
	 */
	public Enumeration<EquipmentMode> getModes()
	{
		if (modes != null) {
			return modes.elements();
		}

		return new Enumeration<EquipmentMode>() {
			public boolean hasMoreElements()
			{
				return false;
			}



			public EquipmentMode nextElement()
			{
				return null;
			}

		};
	}



	/**
	 * Sets the modes that this type of equipment can be in. By default the
	 * EquipmentType doesn't have the modes, so don't try to call this method
	 * with null or empty argument.
	 * 
	 * @param modes non null, non empty list of available mode names.
	 */
	protected void setModes(String[] modes)
	{
		megamek.debug.Assert.assertTrue((modes != null) && (modes.length >= 0),
				"List of modes must not be null or empty");

		if (modes == null) {
			this.modes = new Vector<EquipmentMode>(0);
		}
		else {
			Vector<EquipmentMode> newModes = new Vector<EquipmentMode>(
					modes.length);

			for (String mode : modes) {
				newModes.addElement(EquipmentMode.getMode(mode));
			}

			this.modes = newModes;
		}
	}



	/**
	 * Adds the end turn mode of this type of equipment.
	 * 
	 * @param mode the mode to be added to the <code>endTurnModes</code>.
	 */
	public void addEndTurnMode(String mode)
	{
		endTurnModes.add(mode);
	}



	/**
	 * Some equipment types might have both instant and next turn mode
	 * switching. This method checks for end of turn modes that are kept in a
	 * vector of names. It is used by the {@link Mounted#setMode(int)} method to
	 * distinguish instant and end of turn switching.
	 * 
	 * @param mode - the <code>String</code> of the mode name involved in the
	 *            switch
	 * @return true if the mode name is found in the next turn mode vector
	 */
	public boolean isNextTurnModeSwitch(String mode)
	{
		for (String name : endTurnModes) {
			if (name.equals(mode)) {
				return true;
			}
		}

		return false;
	}



	/**
	 * <p>
	 * Returns the mode number <code>modeNum</code> from the list of modes
	 * available for this type of equipment. Modes are numbered from
	 * <code>0<code> to <code>getModesCount()-1</code>
	 * <p>
	 * Fails if this type of the equipment doesn't have modes, or given mode is
	 * out of the valid range.
	 * 
	 * @param modeNum the mode number.
	 * @return mode number <code>modeNum</code> from the list of modes available
	 *         for this type of equipment.
	 * @see #hasModes()
	 */
	public EquipmentMode getMode(int modeNum)
	{
		megamek.debug.Assert.assertTrue((modes != null) && (modeNum >= 0) &&
				(modeNum < modes.size()));
		return modes.elementAt(modeNum);
	}



	/**
	 * Sets this equipment's mode as being able to be switched instantly.
	 * 
	 * @param bool the Boolean value to store as the
	 *            <code>instantModeSwitch</code>.
	 */
	public void setInstantModeSwitch(boolean bool)
	{
		instantModeSwitch = bool;
	}



	/**
	 * Determines whether or not the mode for this equipment type can be
	 * instantly switched.
	 * 
	 * @return true if the mode can be instantly switched.
	 */
	public boolean hasInstantModeSwitch()
	{
		return instantModeSwitch;
	}



	/**
	 * Sets the internal name of this equipment type.
	 * 
	 * @param str the new internal name.
	 */
	public void setInternalName(String str)
	{
		internalName = str;
		addLookupName(str);
	}



	/**
	 * Adds the lookup name.
	 * 
	 * @param str the lookup name to add.
	 */
	public void addLookupName(String str)
	{
		EquipmentType.lookupHash.put(str.toLowerCase(), this); // static
																// variable
		namesVector.addElement(str); // member variable
	}



	/**
	 * Gets the type.
	 * 
	 * @param name the name of the equipment.
	 * @return the equipment type.
	 */
	public static EquipmentType get(String name)
	{
		if (null == EquipmentType.lookupHash) {
			EquipmentType.initializeTypes();
		}

		return EquipmentType.lookupHash.get(name.toLowerCase().trim());
	}



	/**
	 * Gets the names of all equipments.
	 * 
	 * @return an <code>Enumeration</code> of all the equipment names.
	 */
	public Enumeration<String> getNames()
	{
		return namesVector.elements();
	}



	/**
	 * Initializes the types of equipments.
	 */
	public static void initializeTypes()
	{
		if (null == EquipmentType.allTypes) {
			EquipmentType.allTypes = new Vector<EquipmentType>();
			EquipmentType.lookupHash = new Hashtable<String, EquipmentType>();

			WeaponType.initializeTypes();
			AmmoType.initializeTypes();
			MiscType.initializeTypes();
			BombType.initializeTypes();
		}
	}



	/**
	 * Gets all the equipment types.
	 * 
	 * @return an <code>Enumeration</code> of all equipment types.
	 */
	public static Enumeration<EquipmentType> getAllTypes()
	{
		if (null == EquipmentType.allTypes) {
			EquipmentType.initializeTypes();
		}

		return EquipmentType.allTypes.elements();
	}



	/**
	 * Adds an equipment type.
	 * 
	 * @param type the type of equipment to add.
	 */
	protected static void addType(EquipmentType type)
	{
		if (null == EquipmentType.allTypes) {
			EquipmentType.initializeTypes();
		}

		EquipmentType.allTypes.addElement(type);
	}



	/**
	 * Gets the armor type.
	 * 
	 * @param equipName the equipment name.
	 * @return the armor type.
	 */
	public static int getArmorType(String equipName)
	{
		EquipmentType types = EquipmentType.get(equipName);

		if (types != null) {
			for (int x = 0; x < ARMOR_NAMES.length; x++) {
				if (ARMOR_NAMES[x].equals(types.getInternalName())) {
					return x;
				}
			}
		}

		return T_ARMOR_UNKNOWN;
	}



	/**
	 * Gets the name of an armor type.
	 * 
	 * @param armorType the armor type.
	 * @return the armor type name.
	 */
	public static String getArmorTypeName(int armorType)
	{
		if ((armorType < 0) || (armorType >= ARMOR_NAMES.length)) {
			return "UNKNOWN";
		}

		return ARMOR_NAMES[armorType];
	}



	/**
	 * Gets the structure type.
	 * 
	 * @param equipName the in type
	 * @return the structure type.
	 */
	public static int getStructureType(String equipName)
	{
		EquipmentType types = EquipmentType.get(equipName);

		if (types != null) {
			for (int x = 0; x < STRUCTURE_NAMES.length; x++) {
				if (STRUCTURE_NAMES[x].equals(types.getInternalName())) {
					return x;
				}
			}
		}

		return T_STRUCTURE_UNKNOWN;
	}



	/**
	 * Gets the name of a structure type.
	 * 
	 * @param structureType the structure type.
	 * @return the structure type name.
	 */
	public static String getStructureTypeName(int structureType)
	{
		if ((structureType < 0) || (structureType >= STRUCTURE_NAMES.length)) {
			return "UNKNOWN";
		}

		return STRUCTURE_NAMES[structureType];
	}



	/**
	 * Gets the cost of an equipment.
	 * 
	 * @param entity the equipment whose cost is being retrieved.
	 * @param isArmored whether or not the equipment is armored.
	 * @return The C-Bill cost of the piece of equipment.
	 */
	public double getCost(Entity entity, boolean isArmored)
	{
		return cost;
	}



	/**
	 * Gets the armor cost.
	 * 
	 * // * @param index the index into the <code>ARMOR_COSTS</code> array.
	 * 
	 * @return the armor cost.
	 */
	public static double getArmorCost(int index)
	{
		if ((index < 0) || (index >= ARMOR_COSTS.length)) {
			return -1;
		}

		return ARMOR_COSTS[index];
	}



	/**
	 * Gets the structure cost.
	 * 
	 * @param index the index into the <code>STRUCTURE_COSTS</code> array.
	 * @return the structure cost
	 */
	public static double getStructureCost(int index)
	{
		if ((index < 0) || (index >= STRUCTURE_COSTS.length)) {
			return -1;
		}

		return STRUCTURE_COSTS[index];
	}



	/**
	 * Gets the armor point multiplier.
	 * 
	 * @param index the index of the armor point multiplier to retrieve.
	 * @return the armor point multiplier.
	 */
	public static double getArmorPointMultiplier(int index)
	{
		return getArmorPointMultiplier(index, TechConstants.T_IS_TW_NON_BOX);
	}



	/**
	 * Gets the armor point multiplier.
	 * 
	 * @param index the index of the armor point multiplier to retrieve.
	 * @param inTechLevel the in technical level.
	 * @return the armor point multiplier.
	 */
	public static double getArmorPointMultiplier(int index, int inTechLevel)
	{
		return getArmorPointMultiplier(
				index,
				((inTechLevel == TechConstants.T_CLAN_TW) || (inTechLevel == TechConstants.T_CLAN_ADVANCED)) ||
						(inTechLevel == TechConstants.T_CLAN_EXPERIMENTAL) ||
						(inTechLevel == TechConstants.T_CLAN_UNOFFICIAL));
	}



	/**
	 * Gets the armor point multiplier.
	 * 
	 * @param index the index of the armor point multiplier to retrieve.
	 * @param clanArmor true if is clan armor.
	 * @return the armor point multiplier.
	 */
	public static double getArmorPointMultiplier(int index, boolean clanArmor)
	{
		if ((index < 0) || (index >= ARMOR_POINT_MULTIPLIERS.length)) {
			return POINT_MULTIPLIER_UNKNOWN;
		}

		if ((index == T_ARMOR_FERRO_FIBROUS) && clanArmor) {
			return POINT_MULTIPLIER_CLAN_FF;
		}

		return ARMOR_POINT_MULTIPLIERS[index];
	}



	/**
	 * Resolves the variable cost. Used for stuff like hatchets, which depend on
	 * an unknown quality, usually tonnage of the unit.
	 * 
	 * @param entity whatever has this item.
	 * @param isArmored true if is armored.
	 * @return the resolved cost.
	 */
	public int resolveVariableCost(Entity entity, boolean isArmored)
	{
		int cost = 0;

		if (this instanceof MiscType) {
			if (hasFlag(MiscType.F_MASC)) {
				if (hasSubType(MiscType.S_SUPERCHARGER)) {
					Engine engine = entity.getEngine();
					if (engine == null) {
						cost = 0;
					}
					else {
						cost = engine.getRating() * 10000;
					}
				}
				else {
					int mascTonnage = 0;

					if (getInternalName().equals("ISMASC")) {
						mascTonnage = Math.round(entity.getWeight() / 20.0f);
					}
					else if (getInternalName().equals("CLMASC")) {
						mascTonnage = Math.round(entity.getWeight() / 25.0f);
					}

					cost = entity.getEngine().getRating() * mascTonnage * 1000;
				}
			}
			else if (hasFlag(MiscType.F_TARGCOMP)) {
				int tCompTons = 0;
				float fTons = 0.0f;

				for (Mounted mo : entity.getWeaponList()) {
					WeaponType wType = (WeaponType) mo.getType();
					if (wType.hasFlag(WeaponType.F_DIRECT_FIRE)) {
						fTons += wType.getTonnage(entity);
					}
				}

				if (getInternalName().equals("ISTargeting Computer")) {
					tCompTons = (int) Math.ceil(fTons / 4.0f);
				}
				else if (getInternalName().equals("CLTargeting Computer")) {
					tCompTons = (int) Math.ceil(fTons / 5.0f);
				}

				cost = tCompTons * 10000;
			}
			else if (hasFlag(MiscType.F_CLUB) &&
					(hasSubType(MiscType.S_HATCHET) || hasSubType(MiscType.S_MACE_THB))) {
				int hatchetTons = (int) Math.ceil(entity.getWeight() / 15.0);
				cost = hatchetTons * 5000;
			}
			else if (hasFlag(MiscType.F_CLUB) && hasSubType(MiscType.S_SWORD)) {
				int swordTons = (int) Math.ceil(entity.getWeight() / 15.0);
				cost = swordTons * 10000;
			}
			else if (hasFlag(MiscType.F_CLUB) &&
					hasSubType(MiscType.S_RETRACTABLE_BLADE)) {
				int bladeTons = (int) Math.ceil(0.5f + Math.ceil(entity
						.getWeight() / 20.0));
				cost = (1 + bladeTons) * 10000;
			}
			else if (hasFlag(MiscType.F_TRACKS)) {
				cost = (int) Math.ceil(500 * entity.getEngine().getRating() *
						entity.getWeight() / 75);
			}
			else if (hasFlag(MiscType.F_TALON)) {
				cost = (int) Math.ceil(getTonnage(entity) * 300);
			}
		}
		else {
			if (cost == 0) {
				// if we don't know what it is...
				System.out.println("I don't know how much " + name + " costs.");
			}
		}

		if (isArmored) {
			cost += 150000 * getCriticals(entity);
		}

		return cost;
	}



	/**
	 * Determines if two types are equal.
	 * 
	 * @param equipType the equipment type to determine if equal.
	 * @return true if the two types are equal.
	 */
	public boolean equals(EquipmentType equipType)
	{
		if ((equipType != null) && internalName.equals(equipType.internalName)) {
			return true;
		}

		return false;
	}



	/**
	 * Creates an equipment database.
	 * 
	 * @param file the file used as the database.
	 */
	public static void writeEquipmentDatabase(File file)
	{
		try {
			BufferedWriter writer = new BufferedWriter(new FileWriter(file));
			writer.write("Megamek Equipment Database");
			writer.newLine();
			writer.write("This file can be regenerated with java -jar MegaMek.jar -eqdb ");
			writer.write(file.toString());
			writer.newLine();
			writer.write("Type,Tech Base,Rules,Name,Aliases");
			writer.newLine();

			for (Enumeration<EquipmentType> enumeration = EquipmentType
					.getAllTypes(); enumeration.hasMoreElements();) {
				EquipmentType type = enumeration.nextElement();

				if (type instanceof AmmoType) {
					writer.write("A,");
				}
				else if (type instanceof WeaponType) {
					writer.write("W,");
				}
				else {
					writer.write("M,");
				}

				writer.write(TechConstants.getTechName(type.getTechLevel()));
				writer.write(",");
				writer.write(TechConstants.getLevelName(type.getTechLevel()));
				writer.write(",");

				for (Enumeration<String> names = type.getNames(); names
						.hasMoreElements();) {
					String name = names.nextElement();
					writer.write(name + ",");
				}

				writer.newLine();
			}

			writer.flush();
			writer.close();
		}
		catch (IOException e) {
			e.printStackTrace();
		}
	}



	/**
	 * Creates an equipment extended database.
	 * 
	 * @param file the file used as the database.
	 */
	public static void writeEquipmentExtendedDatabase(File file)
	{
		try {
			BufferedWriter writer = new BufferedWriter(new FileWriter(file));
			writer.write("Megamek Equipment Extended Database");
			writer.newLine();
			writer.write("This file can be regenerated with java -jar MegaMek.jar -eqedb ");
			writer.write(file.toString());
			writer.newLine();
			writer.write("Type,Tech Base,Rules,Name,Tonnage,Crits,Cost,BV");
			writer.newLine();

			for (Enumeration<EquipmentType> enumeration = EquipmentType
					.getAllTypes(); enumeration.hasMoreElements();) {
				EquipmentType type = enumeration.nextElement();

				if (type instanceof AmmoType) {
					writer.write("A,");
				}
				else if (type instanceof WeaponType) {
					writer.write("W,");
				}
				else {
					writer.write("M,");
				}

				writer.write(TechConstants.getTechName(type.getTechLevel()));
				writer.write(",");
				writer.write(TechConstants.getLevelName(type.getTechLevel()));
				writer.write(",");
				writer.write(type.getName());
				writer.write(",");

				String variable = "Variable";

				if (type.tonnage == EquipmentType.TONNAGE_VARIABLE) {
					writer.write(variable);
				}
				else {
					writer.write(Float.toString(type.tonnage));
				}

				writer.write(",");

				if (type.criticals == EquipmentType.CRITICALS_VARIABLE) {
					writer.write(variable);
				}
				else {
					writer.write(Integer.toString(type.criticals));
				}

				writer.write(",");

				if (type.cost == EquipmentType.COST_VARIABLE) {
					writer.write(variable);
				}
				else {
					writer.write(Double.toString(type.getCost(null, false)));
				}

				writer.write(",");

				if (type.battleValue == EquipmentType.BV_VARIABLE) {
					writer.write(variable);
				}
				else {
					writer.write(Double.toString(type.battleValue));
				}

				writer.newLine();
			}

			writer.flush();
			writer.close();
		}
		catch (IOException e) {
			e.printStackTrace();
		}
	}
}
